package com.yupi.springbootinit.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.constant.CommonConstant;
import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.model.dto.chart.ChartQueryRequest;
import com.yupi.springbootinit.model.entity.Chart;
import com.yupi.springbootinit.model.entity.User;
import com.yupi.springbootinit.service.ChartService;
import com.yupi.springbootinit.mapper.ChartMapper;
import com.yupi.springbootinit.service.UserService;
import com.yupi.springbootinit.utils.RedisUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
* @author ning
* @description 针对表【chart(图表信息表)】的数据库操作Service实现
* @createDate 2023-07-30 14:52:51
*/
@Service
public class ChartServiceImpl extends ServiceImpl<ChartMapper, Chart>
    implements ChartService{

    @Resource
    private UserService userService;

    @Override
    public String buildUserInput(Chart chart){
        // 根据预定格式封装用户输入信息
        String chartType = chart.getChartType();
        String goal = chart.getGoal();
        String csvData = chart.getChartData();

        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：\n");

        if(StringUtils.isNotBlank(chartType)){
            goal += "，请使用" + chartType + "的图表类型生成数据";
        }

        userInput.append(goal).append("\n");
        userInput.append("原始数据：\n");
        userInput.append(csvData).append("\n");

        return userInput.toString();
    }

    @Override
    public void handleChartUpdateError(Long chartId, String execMessage){
        Chart updateChartError = new Chart();
        updateChartError.setId(chartId);
        updateChartError.setStatus("failed");
        updateChartError.setExecMessage(execMessage);

        boolean updateChartErrorResult = this.updateById(updateChartError);
        if(!updateChartErrorResult){
            log.error("更新图表失败状态未成功" + chartId + "," + execMessage);
        }
    }

    @Override
    public boolean saveBIResult(String result, Long chartId){
        String[] resultArr = result.split("【【【【");

        if(resultArr.length < 3){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "AI 生成错误");
        }

        String genChart = resultArr[1].trim();
        String genResult = resultArr[2].trim();

        // 防止意外，进行 json 格式转化
        try {
            HashMap<String, Object> genJsonChart = JSONUtil.toBean(genChart, HashMap.class);
            genChart = JSONUtil.toJsonStr(genJsonChart);
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "AI 生成错误，转化 json 失败");
        }

        // 更新数据库，更改状态为成功
        Chart updateChartResult = new Chart();
        updateChartResult.setId(chartId);
        updateChartResult.setGenChart(genChart);
        updateChartResult.setGenResult(genResult);
        updateChartResult.setStatus("succeed");

        return this.updateById(updateChartResult);
    }

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    static final String PAGE_CACHE = "my_chart_page";
    static final Long PAGE_CACHE_TIME = new Long(5);

    @Override
    public Page<Chart> getChartByPageByRedis(ChartQueryRequest chartQueryRequest, User user){
        Long pageSize = chartQueryRequest.getPageSize();
        Long pageNum = chartQueryRequest.getCurrent();

        // 搜索不走 redis
        if(!StringUtils.isBlank(chartQueryRequest.getName())){
            return this.page(new Page<>(pageNum, pageSize), getQueryWrapper(chartQueryRequest, user.getId()));
        }

        // 查询 redis
        Long userId = user.getId();
        String userKey = PAGE_CACHE + ":" + userId;
        String pageKey =  PAGE_CACHE + ":" + pageNum + ":" + pageSize;
        Object redisResult = redisTemplate.opsForHash().get(userKey, pageKey);

        // 查询 数据库
        if("".equals(redisResult)){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }

        if(redisResult == null) {
            Page<Chart> dbResult = this.page(new Page<>(pageNum, pageSize), getQueryWrapper(chartQueryRequest, user.getId()));

            // redis 存空字符串 + ttl 解决缓存穿透
            if(dbResult == null || dbResult.getSize() == 0){
                redisTemplate.opsForHash().put(userKey, pageKey, "");
                redisTemplate.expire(userKey, PAGE_CACHE_TIME, TimeUnit.MINUTES);
                throw  new BusinessException(ErrorCode.NOT_FOUND_ERROR);
            }else{
                redisTemplate.opsForHash().put(userKey, pageKey, dbResult);
                redisTemplate.expire(userKey, PAGE_CACHE_TIME, TimeUnit.MINUTES);
            }

            redisResult = redisTemplate.opsForHash().get(userKey, pageKey);
        }

        // 结果转换
        Page<Chart> result = RedisUtils.convertToPage(redisResult, Chart.class);

        return result;
    }

    @Override
    public QueryWrapper<Chart> getQueryWrapper(ChartQueryRequest chartQueryRequest, Long curUserId) {
        QueryWrapper<Chart> queryWrapper = new QueryWrapper<>();
        if (chartQueryRequest == null) {
            return queryWrapper;
        }
        Long id = chartQueryRequest.getId();
        String name = chartQueryRequest.getName();
        String goal = chartQueryRequest.getGoal();
        String chartType = chartQueryRequest.getChartType();
        Long userId = chartQueryRequest.getUserId();

        // 声明排序字段和排序方式
        String sortField = "createTime";
        String sortOrder = CommonConstant.SORT_ORDER_ASC;

        queryWrapper.eq(id != null && id > 0, "id", id);

        queryWrapper.like(StringUtils.isNotBlank(name), "name", name);
        queryWrapper.eq(StringUtils.isNotBlank(goal), "goal", goal);
        queryWrapper.eq(StringUtils.isNotBlank(chartType), "chartType", chartType);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "userId", userId);
        queryWrapper.eq(userId != null, "userId", userId);

        // 添加当前用户id的限制
        queryWrapper.eq(curUserId != null, "userId", curUserId);

        // 添加排序条件
        queryWrapper.orderBy(true, sortOrder == CommonConstant.SORT_ORDER_DESC, sortField);

        return queryWrapper;
    }
}




